package com.tenbent.product.base.config.security.rest;

import javax.sql.DataSource;

import com.tenbent.product.base.config.datasource.DataSourceConfig;
import com.tenbent.product.center.user.service.UserService;
import com.tenbent.product.center.user.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

//import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;

/**
 * OAuth2 security 安全配置
 *
 * @author Randy
 *
 *
 *         Created by ThinkPad on 2017/6/19.
 */
@Configuration
@EnableWebSecurity
@Import({ DataSourceConfig.class })
@Order(201)
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {

	public static final String USER_SQL = "SELECT login_id , password,true FROM pc_user WHERE login_id = ?";

	public static final String AUTHORITIES_SQL = "SELECT u.login_id, r.role_code FROM pc_role r LEFT JOIN pc_user_role ur ON r.id = ur.role_id LEFT JOIN pc_user u ON ur.user_id = u.id WHERE u.login_id = ?";

	@Autowired
	private DataSource dataSource;

	@Bean
	public TokenStore tokenStore() {
		// return new InMemoryTokenStore();
		return new JdbcTokenStore(dataSource);
	}

	@Bean
	public ClientDetailsService clientDetailsService() {
		ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
		return clientDetailsService;
	}

	@Bean
	public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
		TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
		handler.setTokenStore(tokenStore);
		handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService()));
		handler.setClientDetailsService(clientDetailsService());
		return handler;
	}

	@Bean
	public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
		TokenApprovalStore store = new TokenApprovalStore();
		store.setTokenStore(tokenStore);
		return store;
	}

	@Bean
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	@Bean
	public UserService userDetailsService() {
		return new UserServiceImpl();
	}

	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

	// 配置认证驱动满足加密算法匹配密码
	@Bean
	public DaoAuthenticationProvider authenticationProvider() {
		DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
		authenticationProvider.setUserDetailsService(userDetailsService());
		authenticationProvider.setPasswordEncoder(passwordEncoder());
		return authenticationProvider;
	}

	@Override
	public void configure(AuthenticationManagerBuilder auth) throws Exception {
		// 方式一(内存方式)
		// auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("ADMIN").and().withUser("bob")
		// .password("abc123").roles("USER");

		// （类型二）数据库方式配置用户存储(SQl 查询类型 必须满足security的 字段方式)
		// auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(USER_SQL)
		// .authoritiesByUsernameQuery(AUTHORITIES_SQL);

		// (类型三)数据库方式配置用户存储(自定义扩展 UserDetailsService 接口 类型 推荐方式)
		auth.userDetailsService(userDetailsService());
		// 配置密码加密
		auth.authenticationProvider(authenticationProvider());

	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable().anonymous().disable().authorizeRequests().antMatchers("/oauth/token").permitAll();
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		// 设置不拦截规则
		web.ignoring().antMatchers("/druid/**");
	}
}
